#pragma once

#include "data.hpp"
// #include "httplib.h"
#include "../example/cpp-httplib/httplib.h"
#include <iostream>
#include <string>
#include <functional>

extern cloud::DataManager *_data_manager;

namespace cloud
{
    class Service
    {
    public:
        Service()
        {
            Config *config = Config::GetInstance();
            _server_ip = config->GetServerIp();
            _server_port = config->GetServerPort();
            _download_prefix = config->GetDownloadPrefix();
        }

        bool RunModule()
        {
            std::cout << "run module" << std::endl;
            _server.Post("/upload", Upload);
            _server.Get("/listshow", ListShow);
            _server.Get("/", ListShow);

            std::string download_url = _download_prefix + "(.*)";
            _server.Get(download_url, Download);

            std::cout << _server_ip << ' ' << _server_port << std::endl;
            _server.listen("0.0.0.0", _server_port);
            std::cout << "end module" << std::endl;
            return true;
        }

    private:
        static void Upload(const httplib::Request &req, httplib::Response &rsp)
        {
            // 判断有没有上传的文件区域
            auto ret = req.has_file("file");
            if (ret == false)
            {
                rsp.status = 400;
                return;
            }

            const auto &file = req.get_file_value("file");

            std::string back_dir = Config::GetInstance()->GetBackDir();
            std::string realpath = back_dir + FileUtil(file.filename).FileName();

            FileUtil fu(realpath);
            fu.SetContent(file.content);

            BackupInfo info;
            info.NewBackupInfo(realpath);

            // 向数据管理模块添加
            _data_manager->Insert(info);
        }

        static std::string TimeToStr(time_t t)
        {
            return std::ctime(&t);
        }

        static void ListShow(const httplib::Request &req, httplib::Response &rsp)
        {
            // 获取所有文件的备份信息
            std::vector<BackupInfo> arry;
            _data_manager->GetAll(&arry);

            // 根据备份信息 组织html数据
            std::stringstream ss;
            ss << R"( <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Document</title></head>)";
            ss << R"(<body><h1>Download</h1>)";
            ss << R"(    
                    <form action="http://121.36.198.94:9090/upload" method="post" enctype="multipart/form-data">
                    <div>
                    <input type="file" name="file"><input type="submit" value="上传">
                    </div>
                    </form> 
            )";

            ss << "<table>";
            for (int i = 0; i < arry.size(); i++)
            {
                ss << "<tr>";
                std::string filename = FileUtil(arry[i].real_path).FileName();
                ss << R"(<td><a href = ")" << arry[i].url << R"(">)" << filename << R"(</a></td>)";
                ss << R"(<td align="right">)" << TimeToStr(arry[i].mtime) << "</td>";
                ss << R"(<td align="right">)" << (float)(arry[i].fsize / 1024) << "kb"
                   << "</td>";
                ss << "</tr>";
            }
            ss << "</table>";
            ss << R"(</body></html>)";

            rsp.body = ss.str();
            rsp.set_header("Content-Type", "text/html");
            rsp.status = 200;

            return;
        }

        static std::string GetEtag(const BackupInfo &info)
        {
            FileUtil fu(info.real_path);
            std::string etag = fu.FileName();

            etag += "-";
            etag += std::to_string(info.fsize);

            etag += "-";
            etag += std::to_string(info.mtime);

            return etag;
        }

        static void Download(const httplib::Request &req, httplib::Response &rsp)
        {
            // 1.获取客户端请求的资源路径
            // 2.获得文件备份信息
            BackupInfo info;
            _data_manager->GetOneByUrl(req.path, &info);
            // 3.判断文件是否被压缩
            if (info.pack_flag == true)
            {
                // 解压缩
                FileUtil fu(info.pack_path);
                fu.uncompress(info.real_path);

                // 4.如果压缩删除压缩包,修改备份信息
                fu.Remove();
                info.pack_flag = false;
                _data_manager->Update(info);
            }

            bool retrans = false;
            std::string old_etag;
            if (req.has_header("If-Range"))
            {
                old_etag = req.get_header_value("If-Range");
                if (old_etag == GetEtag(info))
                {
                    retrans = true;
                }
            }
            // 没有If-Range字段,说明是正常下载,或者有这个字段,但和当前文件的etag不一致
            // 也要重新下载

            // 5.读取文件数据,放入body里

            FileUtil fu(info.real_path);

            // 6.设置响应头部字段: Etag 和 Accept-Ranges : bytes
            if (retrans == false)
            {
                fu.GetContent(&rsp.body);
                rsp.set_header("Accept-Ranges", "bytes");
                rsp.set_header("Etag", GetEtag(info));
                rsp.set_header("Content-Type", "application/octet-stream");
                rsp.status = 200;
            }
            else
            {
                //只需要放入body,httplib内部会自动
                fu.GetContent(&rsp.body);
                rsp.set_header("Accept-Ranges", "bytes");
                rsp.set_header("Etag", GetEtag(info));
                rsp.set_header("Content-Type", "application/octet-stream");
                rsp.status = 206;
            }

            return;
        }

    private:
        int _server_port;
        std::string _server_ip;
        std::string _download_prefix;

        httplib::Server _server;
    };

}